﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MathNet.Numerics.Distributions;

namespace OnlineScheduling.DomainModel
{
    public class Instance : ICloneable
    {
        //static int seed = 26;
        //private Random random;
        private Random random = new Random((int)DateTime.Now.Ticks/1024);

        public Instance(int n, int numberOfCPUs, TasksPriorityType priorityType, int minDuration, int maxDuration,int minArrival, int maxArrival, int minWeight, int maxWight, NormalDistribution normal)
        {
            //seed++;
            //random = new Random(seed);
            
            NumberOfTasks = n;
            PriorityType = priorityType;
            MinDuration = minDuration;
            MaxDuration = maxDuration;
            MinArrivalTime = minArrival;
            MaxArrivalTime = maxArrival;
            MinWeight = minWeight;
            MaxWeight = maxWight;
            NumberOfCPUs = numberOfCPUs;
            
            if (normal==null)
            for (int i = 0; i < NumberOfTasks; i++ )
            {
                tasks.Push(
                    new Task(i, random.Next(MinDuration, MaxDuration), random.Next(MinWeight, MaxWeight),
                             PriorityType, random.Next(MinArrivalTime, MaxArrivalTime))
                    );
            }
            else
            {
                
                for (int i = 0; i < NumberOfTasks; i++)
                {
                    int duration=(int)(Math.Ceiling(normal.NextDouble()));

                    double r = random.NextDouble();
                    if (r > 0.9)
                        duration *= 3;
                    else if (r > 0.8)
                        duration *= 2;

                    tasks.Push(
                        new Task(i,duration, random.Next(MinWeight, MaxWeight),
                                 PriorityType, random.Next(MinArrivalTime, MaxArrivalTime))
                        );
                }
            }
        }

        protected Instance()
        {
        }

        public int NumberOfTasks { get; private set; }
        private TasksPriorityType PriorityType { get; set; }
        public int MinDuration { get; private set; }
        public int MaxDuration { get; private set; }
        public int MinArrivalTime { get; private set; }
        public int MaxArrivalTime { get; private set; }
        public int MinWeight { get; private set; }
        public int MaxWeight { get; private set; }
        public int NumberOfCPUs { get; private set; }
        public bool IsEmpty
        {
            get
            {
                return tasks.Count == 0;
            }
        }

        private Heap<Task> tasks = new Heap<Task>();

        public int GetTimeOfNextTask()
        {
            if (tasks.Count == 0) return -1;

            return tasks.Root.TimeIn;
        }

        public Task GetNextTask()
        {
            if (tasks.Count==0) return null;

            return tasks.Pop();
        }

        /// <summary>
        /// Kosztowna zabawa, przelatuje po kopcu, robi liste i potem z powrotem oddaje do kopca
        /// ale my lubimy growe interfejsy i potrzeba danych do grida, jednak warto widzieć co się dzieje
        /// kto to wie czy dobrze liczą te algorytmy.... :P
        /// </summary>
        /// <returns></returns>
        public List<Task> GetCopyList()
        {
            List<Task> list=new List<Task>();

            while(tasks.Count>0) list.Add(tasks.Pop());

            foreach (var task in list)
            {
                tasks.Push(new Task(task.Id,task.Duration,task.Weight,task.PriorityType,task.TimeIn));
            }

            return list;
        }

        #region ICloneable Members

        public object Clone()
        {
            Instance clone = new Instance();

            clone.PriorityType = PriorityType;
            clone.NumberOfTasks = NumberOfTasks;
            clone.NumberOfCPUs = NumberOfCPUs;
            clone.MinWeight = MinWeight;
            clone.MaxWeight = MaxWeight;
            clone.MinDuration = MinDuration;
            clone.MinArrivalTime = MinArrivalTime;
            clone.MaxDuration = MaxDuration;
            clone.MaxArrivalTime = MaxArrivalTime;
            clone.random = random;
            clone.tasks = new Heap<Task>();
            for(int i=0; i< tasks.Count; i++)
            {
                clone.tasks.Push(tasks[i].Clone() as Task);
            }

            return clone;
        }

        #endregion
    }
}
